package com.zhuqi.handler;

import cn.hutool.core.date.DateUtil;
import com.zhuqi.proto.HeartBeat;
import com.zhuqi.proto.build.HeatBeatProtoBuild;
import com.zhuqi.proto.cost.MessageProtocolBufEnum;
import com.zhuqi.service.session.Session;
import com.zhuqi.session.messge.MessagePackage;
import com.zhuqi.util.SpringBeanUtil;
import io.netty.channel.*;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.net.SocketAddress;

/**
 * <p>基础出入站处理器</p>
 * 1. 处理全局异常
 * 2. InActive 事件
 * 3. 闲时心跳(读写)
 * 4. 出站数据类型校验
 * -- 其他事件均实现 用于测试用
 * * @author zhuqi
 * @since 2023/3/10 16:21
 */
@Slf4j
@Component
public class BasicChannelInboundHandler extends ChannelDuplexHandler {

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		log.info("连接出现异常 原因:{}", cause.getMessage());

		ctx.close();
		Session session = SpringBeanUtil.getBean(Session.class);
		session.unbind(ctx.channel());
	}

	/**
	 * 用户下线处理
	 */
	@Override
	public void channelInactive(ChannelHandlerContext ctx) {
		log.info("连接断开，删除会话");
		Session session = SpringBeanUtil.getBean(Session.class);
		session.unbind(ctx.channel());
		ctx.close();
	}

	/**
	 * 闲时心跳机制
	 */
	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		if (evt instanceof IdleStateEvent) {
			IdleState state = ((IdleStateEvent) evt).state();
			// 所有超时
			if (IdleState.ALL_IDLE == state) {
				String now = DateUtil.now();
				Channel channel = ctx.channel();
				HeartBeat.HeartBeatRequest heartBeatRequest = HeatBeatProtoBuild.createHeartBeatRequest("sever", now);
				MessagePackage messagePackage = new MessagePackage();
				messagePackage.setBusinessCode(MessageProtocolBufEnum.HEARTBEAT_REQUEST_MESSAGE.getCode());
				messagePackage.setData(heartBeatRequest.toByteArray());
				log.info("heartBeat:{}", now);
				channel.writeAndFlush(messagePackage);
			}
		} else {
			super.userEventTriggered(ctx, evt);
		}
	}


	/**
	 * 校验数据类型是不是 MessagePackage 不是 抛出异常
	 */
	@Override
	public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
		if (msg instanceof MessagePackage) {
			super.write(ctx, msg, promise);
			return;
		}
		throw new RuntimeException(" 消息类型不是 MessagePackage！！！");
	}

	/**
	 * 缓冲区数据刷新事件
	 * @param ctx               the {@link ChannelHandlerContext} for which the flush operation is made
	 */
	@Override
	public void flush(ChannelHandlerContext ctx) throws Exception {
		super.flush(ctx);
	}

	/**
	 *	连接关闭事件
	 */
	@Override
	public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
		super.close(ctx, promise);
	}


	/**
	 * 读事件
	 */
	@Override
	public void read(ChannelHandlerContext ctx) throws Exception {
		super.read(ctx);
	}

	/**
	 * 写事件
	 */
	@Override
	public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress,
			ChannelPromise promise) throws Exception {
		super.connect(ctx, remoteAddress, localAddress, promise);
	}
}
